//*************************************************************************************
/** \file stl_profiler.cpp
 *    This file contains a class which measures the speed at which functions run. It
 *    keeps basic statistical information so it can calculate the mean, slowest, and 
 *    fastest run times measured during repeated runs of a function. 
 *
 *  Revisions:
 *    \li 12-18-2009 JRR Original file
 *
 *  License:
 *    This file copyright 2009 by JR Ridgely. It is released under the Lesser GNU
 *    public license, version 2. 
 */
//*************************************************************************************


#include "stl_profiler.h"					// The header for this file


//-------------------------------------------------------------------------------------
/** This constructor creates a new profiler object which is ready to measure the speed
 *  at which a piece of code runs. 
 *  @param a_timer A reference to a task timer object which measures real time
 */

stl_profiler::stl_profiler (task_timer& a_timer) : the_timer (a_timer)
{
	clear ();
}


//-------------------------------------------------------------------------------------
/** This method clears the statistical counters so that the profiler is ready to save
 *  some new data. 
 */

void stl_profiler::clear (void)
{
	time_stamp zero (0, 0);
	maximum = zero;
	minimum = zero;
	run_sum = zero;
	average = zero;
	runs = 0L;
}


//-------------------------------------------------------------------------------------
/** This method begins a measurement run. It simply saves the time at which this 
 *  method is called. A subsequent call to end() will cause the duration between the
 *  calls to start() and end() to be measured and recorded. 
 */

void stl_profiler::start (void)
{
	start_time = the_timer.get_time_now ();
}


//-------------------------------------------------------------------------------------
/** This method ends a measurement run, computing the duration of the run and saving
 *  that duration in the statistical counters as necessary. 
 */

void stl_profiler::end (void)
{
	// Compute the duration measured for this run
	time_stamp duration = the_timer.get_time_now () - start_time;

	// A duration less than zero is impossible, so it must be wrong
	if (duration < 0)
	{
		return;
	}

	// If we have a maximum record, save it
	if (duration > maximum)
		maximum = duration;

	// If this is the first run, it's the minimum; otherwise, check it
	if (runs == 0L)
		minimum = duration;
	else
		if (duration < minimum)
			minimum = duration;

	// Add to the counters which are used to find the average
	run_sum += duration;
	runs++;
}


//-------------------------------------------------------------------------------------
/** This method returns the duration of the longest recorded run of the code
 *  which is being profiled. 
 *  @return The maximum measured run duration
 */

const time_stamp& stl_profiler::get_maximum (void) 
{ 
	return (maximum); 
}


//-------------------------------------------------------------------------------------
/** This method returns the duration of the shortest recorded run of the code
 *  which is being profiled. 
 *  @return The minimum measured run duration
 */

const time_stamp& stl_profiler::get_minimum (void) 
{ 
	return (minimum); 
}


//-------------------------------------------------------------------------------------
/** This method returns the average duration of all the runs of the code which
 *  is being profiled. 
 *  @return The average measured run duration
 */

const time_stamp& stl_profiler::get_average (void) 
{ 
	if (runs > 0L)
	{
		average = run_sum;
		average /= runs;
	}
	return (average);
}


//-------------------------------------------------------------------------------------
/** This overloaded shift operator writes the vital statistics for this profiler to a
 *  serial device. 
 *  @param serial A reference to the serial-type object to which to print
 *  @param prof A reference to the profiler whose times are to be displayed
 */

base_text_serial& operator<< (base_text_serial& serial, stl_profiler& prof)
{
	serial << PMS ("runs: ") << prof.get_num_runs ();
	time_stamp fred = prof.get_average ();
	serial << PMS (" avg: ") << fred;
	fred = prof.get_maximum ();
	serial << PMS (" max: ") << fred;
	fred = prof.get_minimum ();
	serial << PMS (" min: ") << fred;
	return (serial);
}
